/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#ifndef MC_BUILTINS_UNPACK_H
#define MC_BUILTINS_UNPACK_H

#include "mcpy/exception.h"
#include <array>
#include <tuple>
#include <type_traits>
#include <vector>

namespace mcpy {

// 直接解包函数：从可迭代对象中获取指定索引的元素
template <std::size_t I, typename Iterable>
auto unpack_get(Iterable&& iterable) {
    using std::begin;
    using std::end;

    auto it     = begin(iterable);
    auto it_end = end(iterable);

    // 跳过前面的元素到达索引 I
    for (std::size_t idx = 0; idx < I; ++idx) {
        if (it == it_end) {
            MC_THROW(mcpy::value_error, "not enough values to unpack");
        }
        ++it;
    }

    // 获取索引 I 的元素
    if (it == it_end) {
        MC_THROW(mcpy::value_error, "not enough values to unpack");
    }

    return *it;
}

// 特化：std::tuple 的直接元素获取
template <std::size_t I, typename... Args>
constexpr auto unpack_get(const std::tuple<Args...>& tuple) {
    static_assert(I < sizeof...(Args), "Index out of bounds");
    return std::get<I>(tuple);
}

template <std::size_t I, typename... Args>
constexpr auto unpack_get(std::tuple<Args...>& tuple) {
    static_assert(I < sizeof...(Args), "Index out of bounds");
    return std::get<I>(tuple);
}

// 特化：std::array 的直接元素获取
template <std::size_t I, typename T, std::size_t N>
constexpr auto unpack_get(const std::array<T, N>& array) {
    static_assert(I < N, "Index out of bounds");
    return array[I];
}

template <std::size_t I, typename T, std::size_t N>
constexpr auto unpack_get(std::array<T, N>& array) {
    static_assert(I < N, "Index out of bounds");
    return array[I];
}

// 特化：mc::array 的直接元素获取
template <std::size_t I, typename T>
auto unpack_get(const mc::array<T>& vec) {
    if (I >= vec.size()) {
        MC_THROW(mcpy::value_error, "not enough values to unpack");
    }
    return vec[I];
}

template <std::size_t I, typename T>
auto unpack_get(mc::array<T>& vec) {
    if (I >= vec.size()) {
        MC_THROW(mcpy::value_error, "not enough values to unpack");
    }
    return vec[I];
}

// 验证解包数量的辅助函数（可选，用于调试）
template <std::size_t Expected, typename Iterable>
void validate_unpack_size(Iterable&& iterable) {
    using std::begin;
    using std::end;

    auto it     = begin(iterable);
    auto it_end = end(iterable);

    std::size_t actual_size = 0;
    while (it != it_end) {
        ++actual_size;
        ++it;
    }

    if (actual_size != Expected) {
        if (actual_size < Expected) {
            MC_THROW(mcpy::value_error, "not enough values to unpack");
        } else {
            MC_THROW(mcpy::value_error, "too many values to unpack");
        }
    }
}

} // namespace mcpy

#endif // MC_BUILTINS_UNPACK_H